﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.Diagnostics;
using System.Windows.Threading;
using System.Threading;

namespace GraduateDesign
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class GameWindow : Window
    {
        //骨骼平滑参数
        private TransformSmoothParameters parameters = new TransformSmoothParameters
        {
            Smoothing = 0.7f,
            Correction = 0.0f,
            Prediction = 0.0f,
            JitterRadius = 0.05f,
            MaxDeviationRadius = 0.04f
        };
        //定时器
        DispatcherTimer timer;
        //kinect设备
        private KinectSensor kinectDevice;
        //储存骨骼信息的数组
        private Skeleton[] frameSkeletons;
        //用以产生随机数
        private Random rand;
        //当前打中的图片数
        private int hitNum;
        //用来控制产生图片速度的参数
        private int count;
        //当前速度
        private int speed;
        //当前等级
        private int grade;
        //丢失的图片数
        private int lostNum;
        //游戏开始提示图片
        private Image beginImage;
        //游戏停止提示图片
        private Image pauseImage;
        //游戏结束提示图片
        private Image gameOverImage;
        //private Image hitImage;
        //背景音乐
        private MediaPlayer backgroundMusic ;
        //打中时的音效
        private MediaPlayer hitMusic;
        //定义挥手类的对象
        private WaveGesture waveGesture;

        private List<BombImage> bombList;

        private List<BombImage> addScoreList;

        public GameWindow()
        {
            InitializeComponent();
            GameInit();
            GameDataInit();
        }

        /// <summary>
        /// 游戏数据的初始化
        /// </summary>
        private void GameDataInit()
        {
            hitNum = 0;
            count = 0;
            speed = 1;
            grade = 1;
            lostNum = 0;
            labelGrade.Content = "1";
            labelScore.Content = "0";
            labelLost.Content = "0";
        }

        /// <summary>
        /// 实例化各个对象，绑定事件
        /// </summary>
        private void GameInit()
        {
            this.KinectDevice = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected);
            //没有kinect设备，则弹出提示
            if (this.KinectDevice==null)
            {
                MessageBox.Show("KinectSensor is Disconnected ! ");
            }
            //绑定当kinect设备状态发生改变时应该触发的事件
            KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;
            //实例化各个对象
            backgroundMusic = new MediaPlayer();
            hitMusic = new MediaPlayer();
            waveGesture = new WaveGesture();
            rand = new Random();
            timer = new DispatcherTimer();
            bombList = new List<BombImage>();
            addScoreList = new List<BombImage>();
            beginImage = NewImage(681, 641, HorizontalAlignment.Stretch, VerticalAlignment.Stretch);
            pauseImage = NewImage(681, 641, HorizontalAlignment.Stretch, VerticalAlignment.Stretch);
            gameOverImage = NewImage(681, 641, HorizontalAlignment.Stretch, VerticalAlignment.Stretch);
            //绑定当挥手手势完成后应该触发的事件
            waveGesture.GestureDetected += new EventHandler(waveGesture_GestureDetected);
            backgroundMusic.MediaEnded += new EventHandler(backgroundMusic_MediaEnded);
            //定时器间隔事件设定
            timer.Interval = TimeSpan.FromSeconds(0.01);
            //绑定当定时器时间到达时应该触发的事件
            timer.Tick += new EventHandler(timer_Tick);
        }

        /// <summary>
        /// 窗口载入后，载入图片进行操作提示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            AddImageToCanvas(beginImage, "i15", 0, 0, GameCanvas);
        }

        /// <summary>
        /// 检测到挥手手势后，触发该事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void waveGesture_GestureDetected(object sender, EventArgs e)
        {
            //移除提示图片
            if (GameCanvas.Children.Contains(beginImage))
            {
                GameCanvas.Children.Remove(beginImage);
            }
            else if (GameCanvas.Children.Contains(pauseImage))
            {
                GameCanvas.Children.Remove(pauseImage);
            }
            else if (GameCanvas.Children.Contains(gameOverImage))
            {
                GameCanvas.Children.Remove(gameOverImage);
                GameDataInit();
            }
            //定时器启动
            timer.Start();
            //播放背景音乐
            backgroundMusic.Open(new Uri(Environment.CurrentDirectory + "\\music\\backMusic.wav", UriKind.Relative));
            backgroundMusic.Play();
        }

        //kinect的属性
        public KinectSensor KinectDevice
        {
            get { return this.kinectDevice; }
            set
            {
                if (this.kinectDevice != value)
                {
                    //Uninitialize
                    if (this.kinectDevice != null)
                    {
                        this.kinectDevice.Stop();
                        this.KinectDevice.ColorFrameReady -= KinectDevice_ColorFrameReady;
                        this.kinectDevice.SkeletonFrameReady -= KinectDevice_SkeletonFrameReady;
                        SkeletonViewerElement.KinectDevice = null;
                        this.frameSkeletons = null;
                        this.kinectDevice.SkeletonStream.Disable();
                    }

                    this.kinectDevice = value;

                    //Initialize
                    if (this.kinectDevice != null)
                    {
                        if (this.kinectDevice.Status == KinectStatus.Connected)
                        {
                            this.kinectDevice.ColorStream.Enable();
                            this.kinectDevice.SkeletonStream.Enable(parameters);
                            this.kinectDevice.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);
                            this.frameSkeletons = new Skeleton[this.kinectDevice.SkeletonStream.FrameSkeletonArrayLength];
                            SkeletonViewerElement.KinectDevice = this.KinectDevice;
                            this.kinectDevice.Start();
                            this.KinectDevice.ColorFrameReady += KinectDevice_ColorFrameReady;
                            this.kinectDevice.SkeletonFrameReady += KinectDevice_SkeletonFrameReady;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 背景音乐控制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void backgroundMusic_MediaEnded(object sender, EventArgs e)
        {
            backgroundMusic.Open(new Uri(Environment.CurrentDirectory + "\\music\\backMusic.wav", UriKind.Relative));
            backgroundMusic.Play();
        }

        /// <summary>
        /// 定时器到点后，出发该事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer_Tick(object sender, EventArgs e)
        {
            count++;
            //移除脱离GameCanvas的image
            for (int i = 0; i < GameCanvas.Children.Count; i++)
            {
                Canvas.SetTop(GameCanvas.Children[i], Canvas.GetTop(GameCanvas.Children[i]) + speed);
                if (Canvas.GetTop(GameCanvas.Children[i]) > GameCanvas.Height)
                {
                    GameCanvas.Children.RemoveAt(i);
                    lostNum++;
                    if (lostNum >= 5)
                    {
                        timer.Stop();
                        GameCanvas.Children.Clear();
                        AddImageToCanvas(gameOverImage,"i17", 0, 0, GameCanvas);
                    }
                    labelLost.Content = lostNum.ToString();
                }
            }

            //移除碰撞后产生的对象
            for (int i = 0; i < bombList.Count; i++)
            {
                bombList[i].move(bombList[i].image, 2 * speed);
                bombList[i].Disappear(bombList[i].image, bombList, i,0.05f);
            }

            for (int i = 0; i < addScoreList.Count; i++)
            {
                addScoreList[i].move(addScoreList[i].image, -1);
                addScoreList[i].Disappear(addScoreList[i].image, addScoreList, i,0.01f);
            }
            //根据等级的不同，在一定间隔时间内新建一个image控件
            if (count * grade >= 100)
            {
                Image image = NewImage(60, 60, HorizontalAlignment.Stretch, VerticalAlignment.Stretch);
                AddImageToCanvas(image, "i"+rand.Next(8).ToString(), rand.Next((int)GameCanvas.Width - 50), 0, GameCanvas);
                count = 0;
            }
        }

        /// <summary>
        /// 产生游戏元素或游戏提示图片
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="height">图片高度</param>
        /// <param name="width">图片宽度</param>
        /// <param name="imageName">图片名称</param>
        /// <param name="x">图片所在位置X值</param>
        /// <param name="y">图片所在位置X值</param>
        /// <param name="canvas"></param>
        /// <returns></returns>
        private void AddImageToCanvas(Image image,string imageName, int x, int y, Canvas canvas)
        {
            image.Name = imageName;
            image.Source = new BitmapImage(new Uri("/GraduateDesign;component/Images/" + imageName+".png", UriKind.Relative));
            Canvas.SetLeft(image, x);
            Canvas.SetTop(image, y);
            canvas.Children.Add(image);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void KinectDevice_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame == null)
                {
                    return;
                }
                byte[] pixels = new byte[colorFrame.PixelDataLength];
                colorFrame.CopyPixelDataTo(pixels);
                int stride = colorFrame.Width * 4;
                PeopleShow.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null, pixels, stride);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void KinectDevice_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            using (SkeletonFrame frame = e.OpenSkeletonFrame())
            {
                if (frame == null)
                {
                    return;
                }
                else
                {
                    frame.CopySkeletonDataTo(frameSkeletons);
                    waveGesture.Update(frameSkeletons, 5050);
                    Skeleton skeleton = GetPrimarySkeleton(this.frameSkeletons);
                    if (timer.IsEnabled)
                    {
                        if (skeleton != null)
                        {
                            TrackJoint(skeleton.Joints[JointType.HandRight]);
                            TrackJoint(skeleton.Joints[JointType.HandLeft]);
                            TrackJoint(skeleton.Joints[JointType.FootRight]);
                            TrackJoint(skeleton.Joints[JointType.FootLeft]);
                        }
                        else
                        {
                            timer.Stop();
                            backgroundMusic.Pause();
                            AddImageToCanvas(pauseImage, "i16", 0, 0, GameCanvas);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 跟踪关节点
        /// </summary>
        /// <param name="joint">关节</param>
        private void TrackJoint(Joint joint)
        {
            if (joint.TrackingState != JointTrackingState.Tracked)
            {
                return;
            }
            else
            {
                if (GameCanvas.Children.Count > 0)
                {
                    foreach (Image item in GameCanvas.Children)
                    {
                        //检测到碰撞，就移除相应控件
                        if (HitTest(joint, item))
                        {
                            HitedOperation(item); 
                            break;
                        }
                    }
                }
            }
        }

       /// <summary>
        /// 击中图片之后的操作
       /// </summary>
       /// <param name="image"></param>
        private void HitedOperation(Image image)
        {
            //播放击中时的音效
            hitMusic.Open(new Uri(Environment.CurrentDirectory + "\\music\\bomb.wav", UriKind.Relative));
            hitMusic.Play();
            //击中数量加1
            hitNum++;
            labelScore.Content = hitNum.ToString();
            //判断等级是否提升
            if (hitNum != 0 && hitNum % 5 == 0)
            {
                //等级提升
                grade++;
                labelGrade.Content = grade.ToString();
                //速度提升
                speed += 1;
            }
            BombImage bomb = new BombImage((int)Canvas.GetLeft(image), (int)Canvas.GetTop(image), 100, 120);
            BombImage addScore=new BombImage((int)Canvas.GetLeft(image),(int)Canvas.GetTop(image), 60, 60);
            //移除相应控件
            GameCanvas.Children.Remove(image);
            image.Source = null;
            bomb.image = NewImage(bomb.height, bomb.width,HorizontalAlignment.Stretch,VerticalAlignment.Stretch);
            addScore.image = NewImage(addScore.height, addScore.width, HorizontalAlignment.Stretch, VerticalAlignment.Stretch);
            bool isOK=int.TryParse(image.Name.Remove(0, 1), out bomb.index);
            if (isOK)
            {
                AddImageToCanvas(bomb.image, "i" + (bomb.index + 19).ToString(), bomb.locationX, bomb.locationY, BombCanvas);
                AddImageToCanvas(addScore.image, "addScore", addScore.locationX, addScore.locationY, BombCanvas);
            }
            bombList.Add(bomb);
            addScoreList.Add(addScore);
        }

        /// <summary>
        /// 检测关节点是否与控件有碰撞
        /// </summary>
        /// <param name="joint"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        private bool HitTest(Joint joint, UIElement target)
        {
            return (GetHitTarget(joint, target) != null);
        }

        /// <summary>
        /// 获取关节点与控件的重叠位置
        /// </summary>
        /// <param name="joint"></param>
        /// <param name="target"></param>
        /// <returns></returns>
        private IInputElement GetHitTarget(Joint joint, UIElement target)
        {
            Point targetPoint = LayoutRoot.TranslatePoint(GetJointPoint(joint), target);
            return target.InputHitTest(targetPoint);
        }

        /// <summary>
        /// 获取关节点的二维坐标
        /// </summary>
        /// <param name="joint"></param>
        /// <returns></returns>
        private Point GetJointPoint(Joint joint)
        {
            DepthImagePoint point = this.KinectDevice.MapSkeletonPointToDepth(joint.Position, this.KinectDevice.DepthStream.Format);
            point.X *= (int)this.GameCanvas.ActualWidth / KinectDevice.DepthStream.FrameWidth;
            point.Y *= (int)this.GameCanvas.ActualHeight / KinectDevice.DepthStream.FrameHeight;
            return new Point(point.X, point.Y + 220);
        }

        /// <summary>
        /// 获取离kinect最近的人物骨骼
        /// </summary>
        /// <param name="skeletons"></param>
        /// <returns></returns>
        private static Skeleton GetPrimarySkeleton(Skeleton[] skeletons)
        {
            Skeleton skeleton = null;
            if (skeletons != null)
            {
                //查找最近的游戏者
                for (int i = 0; i < skeletons.Length; i++)
                {
                    if (skeletons[i].TrackingState == SkeletonTrackingState.Tracked)
                    {
                        if (skeleton == null)
                        {
                            skeleton = skeletons[i];
                        }
                        else
                        {
                            if (skeleton.Position.Z > skeletons[i].Position.Z)
                            {
                                skeleton = skeletons[i];
                            }
                        }
                    }
                }
            }
            return skeleton;
        }

        /// <summary>
        /// kinect状态发生改变时触发该事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case KinectStatus.Initializing:
                case KinectStatus.Connected:
                case KinectStatus.NotPowered:
                case KinectStatus.NotReady:
                case KinectStatus.DeviceNotGenuine:
                    this.KinectDevice = e.Sensor;
                    break;
                case KinectStatus.Disconnected:
                    //TODO: Give the user feedback to plug-in a Kinect device.                    
                    this.KinectDevice = null;
                    break;
                default:
                    //TODO: Show an error state
                    break;
            }
        }

        /// <summary>
        /// 创建图片，给其各个属性赋值
        /// </summary>
        /// <param name="height"></param>
        /// <param name="width"></param>
        /// <param name="horiaontalAlignment"></param>
        /// <param name="verticalAlignment"></param>
        /// <returns></returns>
        private Image NewImage(int height, int width, HorizontalAlignment horiaontalAlignment, VerticalAlignment verticalAlignment)
        {
            Image image = new Image();
            image.Height = height;
            image.Width = width;
            image.HorizontalAlignment = horiaontalAlignment;
            image.VerticalAlignment = verticalAlignment;
            return image;
        }

        /// <summary>
        /// 窗口关闭后，停止定时器，停止背景音乐，清除canvas上的所有控件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closed(object sender, EventArgs e)
        {
            if (timer.IsEnabled)
            {
                timer.Stop();
            }
            backgroundMusic.Stop();
            hitMusic.Stop();
            GameCanvas.Children.Clear();
            BombCanvas.Children.Clear();
        }
    }
}
